package ar.com.cubika.trainees.bean.transportes.actividades;

import java.util.Date;

import ar.com.cubika.trainees.bean.transportes.Ruta;
import ar.com.cubika.trainees.bean.transportes.vehiculos.Vehiculo;
import ar.com.cubika.trainees.date.DateUtils;
import ar.com.cubika.trainees.date.RangoDeFechas;
import ar.com.cubika.trainees.exceptions.BusinessException;

/**
 * Representa cada viaje que debe llevar a cabo la empresa de transportes
 * 
 * @author
 */
public class Viaje implements Actividad {
	private Ruta ruta;
	private long carga;
	private double tiempoMaximo;
	private Date fechaPartida;
	private Vehiculo vehiculo;
	private String chofer;

	/**
	 * Constructor comodo
	 */
	public Viaje(Ruta ruta, long carga, double tiempoMaximo) {
		this();
		this.ruta = ruta;
		this.carga = carga;
		this.tiempoMaximo = tiempoMaximo;
	}

	/**
	 * Para Hibernate
	 */
	public Viaje() {
	}

	/**
	 * Asigna el viaje a un vehiculo
	 * 
	 * @param veh
	 *            el vehiculo al que se asigna el viaje
	 * @see Vehiculo#addViaje(Viaje)
	 * @throws BusinessException
	 *             si el viaje ya tenia un vehiculo asignado
	 * @throws BusinessException
	 *             si el vehiculo no puede hacer el viaje
	 */
	public synchronized void asignar(Vehiculo veh) throws BusinessException {
		
			if (this.isAsignado()) {
				throw new BusinessException("Viaje " + this
						+ "ya tiene un vehiculo asignado");
			} else if (!veh.puedeHacer(this)) {
				throw new BusinessException("Vehiculo " + veh
						+ " no puede hacer el viaje " + this);
			}
			this.vehiculo = veh;
			veh.addViaje(this);
		
	}

	public String getChofer() {
		return chofer;
	}

	public void setChofer(String chofer) {
		this.chofer = chofer;
	}

	/**
	 * Desasigna el viaje, o sea le saca el vehiculo que lo tenia asignado.
	 * 
	 * @see Vehiculo#removeViaje(Viaje)
	 * @throws BusinessException
	 *             si el viaje no tiene vehiculo asignado
	 */
	public synchronized void desasignar() {
		this.checkViajeAsignado();
		this.vehiculo.removeViaje(this);
		this.vehiculo = null;
	}

	/**
	 * La carga que debe llevar el viaje, en kilos
	 */
	public long getCarga() {
		return carga;
	}

	/**
	 * La ruta que va a seguir el viaje
	 */
	public Ruta getRuta() {
		return ruta;
	}

	/**
	 * El vehiculo que tiene asignado el viaje
	 */
	public Vehiculo getVehiculo() {
		return this.vehiculo;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * ar.com.cubika.trainees.bean.transportes.actividades.Actividad#getDescripcion
	 * ()
	 */
	public String getDescripcion() {
		return "Viaje: " + this.getRuta();
	}

	/**
	 * Indica si el viaje esta asignado a un vehiculo
	 * 
	 * @return un boolean
	 */
	public synchronized boolean isAsignado() {
		return this.vehiculo != null;
	}

	/**
	 * El limite de tiempo para el viaje, en horas
	 */
	public double getTiempoMaximo() {
		return tiempoMaximo;
	}

	/**
	 * El tiempo que se estima para este viaje, en horas. Depende del vehiculo
	 * asignado.
	 * 
	 * @throws BusinessException
	 *             si el viaje no tiene vehiculo asignado
	 */
	public double getTiempoEstimado() {
		this.checkViajeAsignado();
		return this.vehiculo.getTiempo(this);
	}

	/**
	 * El origen del viaje
	 */
	public String getOrigen() {
		return ruta.getOrigen();
	}

	/**
	 * El destino del viaje
	 */
	public String getDestino() {
		return ruta.getDestino();
	}

	/**
	 * La cantidad total de km del viaje
	 */
	public long getKm() {
		return ruta.getKm();
	}

	/**
	 * La cantidad de km de camino en buen estado
	 */
	public long getKmBuenCamino() {
		return ruta.getKmBuenCamino();
	}

	/**
	 * La cantidad de km de camino en buen estado
	 */
	public long getKmMalCamino() {
		return ruta.getKmMalCamino();
	}

	/**
	 * La fecha en la que empieza el viaje
	 */
	public Date getFechaPartida() {
		return fechaPartida;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * ar.com.cubika.trainees.bean.transportes.actividades.Actividad#incluyeFecha
	 * (java.util.Date)
	 */
	public boolean incluyeFecha(Date fecha) {
		Date fechaHasta = DateUtils.addDays(this.getFechaPartida(),
				this.getDiasEstimados());
		return new RangoDeFechas(this.getFechaPartida(), fechaHasta)
				.incluye(fecha);
	}

	/**
	 * La cantidad de dias enteros incluidos en la duracion estimada del viaje.
	 */
	protected long getDiasEstimados() {
		return Math.round(Math.floor((this.getTiempoEstimado() + 1E-8) / 24));
	}

	/**
	 * Chequea que el viaje esta asignado, en ese caso lanza una excepcion.
	 * 
	 * @throws BusinessException
	 *             si el viaje no tiene vehiculo asignado
	 */
	protected void checkViajeAsignado() {
		if (!this.isAsignado()) {
			throw new BusinessException("Viaje " + this
					+ " sin vehiculo asignado");
		}
	}

	public void setCarga(long carga) {
		this.carga = carga;
	}

	public void setRuta(Ruta ruta) {
		this.ruta = ruta;
	}

	public void setTiempoMaximo(double tiempoMaximo) {
		this.tiempoMaximo = tiempoMaximo;
	}

	public void setFechaPartida(Date fechaPartida) {
		this.fechaPartida = fechaPartida;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.lang.Object#toString()
	 */
	public String toString() {
		return this.getRuta() + " llevando " + this.getCarga();
	}

	public void setVehiculo(Vehiculo vehiculo) {
		this.vehiculo = vehiculo;
	}

}
